<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <link href='https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css' rel='stylesheet' />
  <style>
      html,
      body,
      #map {
          width: 100%;
          height: 100%;
          margin: 0;
          padding: 0;
          overflow: hidden;
      }
      .button-box {
          position: absolute;
          top: 20px;
          left: 20px;
          z-index: 99;
      }
      .draw-tooltips {
          padding: 0 3px;
          background-color: rgba(255,255,255, 0.6);
          border-radius: 4px;
      }
  </style>
</head>
<body>
<div id="map">
  <div class="button-box">
    <button onclick="drawTools.activeDraw('point')">绘制点</button>
    <button onclick="drawTools.activeDraw('line')">绘制线</button>
    <button onclick="drawTools.activeDraw('polygon')">绘制面</button>
    <button onclick="drawTools.activeDraw('rect')">矩形</button>
    <button onclick="drawTools.activeDraw('circle')">圆形</button>
    <button onclick="drawTools.clearDraw()">清除</button>
  </div>
</div>
<script src='https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js'></script>
<script src="https://unpkg.com/@turf/turf@6.3.0/turf.min.js"?></script>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
    const style = {
        "version": 8,
        "name": "lzugis", // dark, light, pink
        "sources": {
            "nav": {
                "type": "raster",
                "tiles": ['https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'],
                "tileSize": 256
            }
        },
        "layers": [{
            "id": "nav",
            "type": "raster",
            "source": "nav",
            "minzoom": 0,
            "maxzoom": 17
        }]
    }
    const dom = document.getElementById('map');
    window.map = new mapboxgl.Map({
        container: dom,
        style: style,
        center: [103.081163, 37.1612],
        zoom: 3.5,
        minZoom: 2,
        maxZoom: 18
    });

    var drawTools = {
        points: [],
        tooltip: null,
        isDraw: false,
        drawType: '',
        linesFeatures: [],
        pointsFeatures: [],
        init() {
            const that = this
            // 初始化提示信息
            const ele = document.createElement('div');
            ele.setAttribute('class', 'draw-tooltips');
            const option = {
                element: ele,
                anchor: 'left',
                offset: [10, 0]
            };
            this.tooltip = new mapboxgl.Marker(option)
                .setLngLat([10, 0])
                .addTo(map);

            // 添加面source和layer
            // 面积
            map.addSource('draw-polygon', {
                type: 'geojson',
                data: null
            })
            map.addLayer({
                'id': 'draw-polygon-fill',
                'source': 'draw-polygon',
                'type': 'fill',
                'paint': {
                    'fill-color': 'red',
                    'fill-opacity': 0.1
                }
            })
            map.addLayer({
                'id': 'draw-polygon-stroke',
                'source': 'draw-polygon',
                'type': 'line',
                'paint': {
                    'line-color': 'red',
                    'line-width': 3
                }
            })
            // 距离
            map.addSource('draw-line', {
                type: 'geojson',
                data: null
            })
            map.addLayer({
                'id': 'draw-line',
                'source': 'draw-line',
                'type': 'line',
                'paint': {
                    'line-color': 'red',
                    'line-width': 3
                }
            })
            // 点
            map.addSource('draw-point', {
                type: 'geojson',
                data: null
            })
            map.addLayer({
                'id': 'draw-point',
                'source': 'draw-point',
                'type': 'circle',
                'paint': {
                    'circle-radius': 2,
                    'circle-color': 'white',
                    'circle-stroke-color': 'red',
                    'circle-stroke-width': 2
                }
            })

            map.on('click', e => {
                if(that.isDraw) {
                    const lonlat = e.lngLat.toArray()
                    that.points.push(lonlat)
                    that.showPoints();
                    switch (that.drawType) {
                        case 'line': {
                            const line = turf.lineString(that.points);
                            that.linesFeatures.push(line)
                            map.getSource('draw-line').setData(that.getGeojson(that.linesFeatures))
                            break;
                        }
                        case 'rect': {
                            that.setRectData(that.points, true)
                            break;
                        }
                        case 'circle': {
                            that.setCircleData(that.points, true)
                            break;
                        }
                    }
                }
            })
            map.on('mousemove', e => {
                if(that.isDraw) {
                    const lonlat = e.lngLat.toArray()
                    const len = that.points.length
                    let tooltip = len === 0 ? '点击鼠标开始绘制' : '双击鼠标结束绘制'
                    if(that.drawType === 'polygon' && len === 1) {
                        tooltip = '点击鼠标继续绘制'
                    }
                    if('rect, circle'.indexOf(that.drawType) !== -1) {
                        tooltip = '点击鼠标结束绘制'
                    }
                    that.tooltip.getElement().innerText = tooltip
                    that.tooltip.setLngLat(lonlat)
                    switch (that.drawType) {
                        case 'line': {
                            const points = that.points.concat([lonlat])
                            const line = turf.lineString(points);
                            const lineFeatures = that.linesFeatures.concat([])
                            lineFeatures.push(line)
                            map.getSource('draw-line').setData(that.getGeojson(lineFeatures))
                            break;
                        }
                        case 'polygon': {
                            if(len > 1) {
                                let points = [
                                    that.points.concat([lonlat, that.points[0]])
                                ]
                                const polygon = turf.polygon(points);
                                map.getSource('draw-polygon').setData(polygon)
                            }
                            break;
                        }
                        case 'rect': {
                            const points = that.points.concat([lonlat])
                            that.setRectData(points, false)
                            break;
                        }
                        case 'circle': {
                            const points = that.points.concat([lonlat])
                            that.setCircleData(points, false)
                            break;
                        }
                    }
                }
            })
            map.on('dblclick', e => {
                if(that.isDraw) {
                    that.endDraw()
                }
            })
        },
        setRectData(points, isEnd) {
            if(points.length !== 2) return
            const pt1 = points[0]
            const pt2 = points[1]
            const pts = [[
                pt1,
                [pt2[0], pt1[1]],
                pt2,
                [pt1[0], pt2[1]],
                pt1
            ]]
            const polygon = turf.polygon(pts);
            map.getSource('draw-polygon').setData(polygon)
            if(isEnd) this.endDraw()
        },
        setCircleData(points, isEnd) {
            if(points.length !== 2) return
            const center = points[0]
            const line = turf.lineString(points);
            const dis = turf.length(line);
            const polygon = turf.buffer(turf.point(center), dis)
            map.getSource('draw-polygon').setData(polygon)
            map.getSource('draw-line').setData(line)
            if(isEnd) this.endDraw()
        },
        showPoints() {
            this.points.forEach(pt => {
                this.pointsFeatures.push(turf.point(pt))
            })
            map.getSource('draw-point').setData(this.getGeojson(this.pointsFeatures))
        },
        getGeojson(features) {
            return {
                "type": "FeatureCollection",
                "features": features
            }
        },
        endDraw() {
            this.drawType = ''
            this.isDraw = false
            this.tooltip.setLngLat([0, 0])
        },
        activeDraw(type) {
            this.isDraw = true
            this.drawType = type
            map.getCanvas().style.cursor = 'default'
            map.doubleClickZoom.disable()
            this.points = []
        },
        // 清楚测量结果
        clearDraw() {
            const json = {
                'type': 'FeatureCollection',
                'features': []
            }
            map.getSource('draw-polygon').setData(json)
            map.getSource('draw-line').setData(json)
            map.getSource('draw-point').setData(json)
            this.tooltip.setLngLat([0, 0])
            this.points = []
        }
    }

    map.on('load', () => {
        drawTools.init()
        const url = 'http://39.106.122.204:8086/geoserver/world/wms' + '?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&layers=world:base_province'
        this.map.addSource('wms-test-source', {
            'type': 'raster',
            'tiles': [url],
            'tileSize': 256
        })
        this.map.addLayer(
            {
                'id': 'wms-test-layer',
                'type': 'raster',
                'source': 'wms-test-source',
                'paint': {
                    'raster-opacity': 1
                }
            }
        )
    })
</script>
</body>
</html>